﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;

namespace MathService.NeuralNetworks
{
    public class Neuron : INeuron
    {
        //public static class ActivationFunctions
        //{
        //    public static double Sigmoid(double x) { return 1 / (1 + Math.Exp(-x)); }

        //    public static double dSigmoid(double x)
        //    {
        //        var e = Math.Exp(-x);
        //        var e2 = 1 + e;
        //        return e / e2 / e2;
        //    }

        //    public static double Sign(double x) { return Math.Sign(x); }
        //}

        private readonly IList<INeuralInput> f_Imputs = new List<INeuralInput>();

        private NeuralActivationFunction f_ActivationFunction = ActivationFunctions.Logistic();

        public IList<INeuralInput> Imputs { get { return f_Imputs; } }

        public double Value { get; private set; }

        public double Offset { get; set; }

        public NeuralActivationFunction ActivationFunction
        {
            get { return f_ActivationFunction; }
            set
            {
                Contract.Ensures(f_ActivationFunction != null, @"Функция активации не может быть пустой");
                f_ActivationFunction = value;
            }
        }

        public Neuron()
        {
            Contract.Ensures(f_ActivationFunction != null);
            Contract.Ensures(f_Imputs != null);
        }
        public Neuron(NeuralActivationFunction F)
        {
            Contract.Requires(F != null, @"Функция активации не может быть пустой");
            Contract.Ensures(f_ActivationFunction != null);
            f_ActivationFunction = F;
        }
        public Neuron(IList<INeuralInput> Inputs, NeuralActivationFunction F)
            : this(F)
        {
            Contract.Requires(Inputs != null, @"Список входов не может отсутствовать");
            Contract.Ensures(f_Imputs != null);
            f_Imputs = Inputs;
        }

        public double GetValue()
        {
            var result = 0.0;
            for(var i = 0; i < f_Imputs.Count; i++)
                result += f_Imputs[i].WeightValue;
            return Value = f_ActivationFunction(result + Offset);
        }
    }
}